package network.byteConversions;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

import network.dataFormats.GroToGO;
import tools.Point;
public class ByteConverter {
	public static final byte[] intToBytes(int value) {
		return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value};
	}
	public static final int bytesToInt(byte[] b) {
		return (b[0] << 24) + ((b[1] & 0xFF) << 16) + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF);
	}
	public static final int bytesToInt(byte[] b, int offset) {
		return (b[0 + offset] << 24) + ((b[1 + offset] & 0xFF) << 16) + ((b[2 + offset] & 0xFF) << 8) + (b[3 + offset] & 0xFF);
	}
	public static int fourBytesToInt(byte b0, byte b1, byte b2, byte b3) {
		return (b0 << 24) + ((b1 & 0xFF) << 16) + ((b2 & 0xFF) << 8) + (b3 & 0xFF);
	}
	public static void intToFourBytes(int value, byte[] data, int offset) {
		data[offset] = (byte) (value >>> 24);
		data[offset + 1] = (byte) (value >>> 16);
		data[offset + 2] = (byte) (value >>> 8);
		data[offset + 3] = (byte) value;
	}
	public static Point bytesToPoint(byte[] data) {
		float x = Float.intBitsToFloat(fourBytesToInt(data[0], data[1], data[2], data[3]));
		float y = Float.intBitsToFloat(fourBytesToInt(data[4], data[5], data[6], data[7]));
		return new Point(x, y);
	}
	public static Point bytesToPoint(byte[] data, int i) {
		float x = Float.intBitsToFloat(fourBytesToInt(data[0 + i], data[1 + i], data[2 + i], data[3 + i]));
		float y = Float.intBitsToFloat(fourBytesToInt(data[4 + i], data[5 + i], data[6 + i], data[7 + i]));
		return new Point(x, y);
	}
	public static float bytesToFloat(byte[] data) {
		return Float.intBitsToFloat(fourBytesToInt(data[0], data[1], data[2], data[3]));
	}
	public static byte[] pointToBytes(Point p) {
		byte[] k = new byte[8];
		byte[] b1 = floatToBytes(p.x);
		byte[] b2 = floatToBytes(p.y);
		k[0] = b1[0];
		k[1] = b1[1];
		k[2] = b1[2];
		k[3] = b1[3];
		k[4] = b2[0];
		k[5] = b2[1];
		k[6] = b2[2];
		k[7] = b2[3];
		return k;
	}
	public static byte[] floatToBytes(float x) {
		return intToBytes(Float.floatToIntBits(x));
	}
	public static final boolean byteToBoolean(byte b) {
		return (b == 1 ? true : false);
	}
	public static final byte booleanToByte(boolean b) {
		return (b ? (byte) 1 : (byte) 0);
	}
	public static char byteToChar(byte b) {
		return (char) b;
	}
	public static byte charToByte(char c) {
		return (byte) c;
	}
	public static byte[] twoIntsToBytes(int value, int value2) {
		return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value, (byte) (value2 >>> 24), (byte) (value2 >>> 16), (byte) (value2 >>> 8), (byte) value2};
	}
	public static int[] bytesToTwoInts(byte[] b) {
		return new int[]{fourBytesToInt(b[0], b[1], b[2], b[3]), fourBytesToInt(b[4], b[5], b[6], b[7])};
	}
	// TODO delete the serial stuff, was too lazy to make a good implementation
	// -.- its not that much effort
	public static byte[] groToGOToData(GroToGO g) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutput out;
		try {
			out = new ObjectOutputStream(bos);
			out.writeObject(g);
			byte[] bytes = bos.toByteArray();
			out.close();
			bos.close();
			return bytes;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static GroToGO groToGOFromData(byte[] bytes) {
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
		try {
			ObjectInput in = new ObjectInputStream(bis);
			Object o = in.readObject();
			bis.close();
			in.close();
			return (GroToGO) o;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static void floatToFourBytes(float value, byte[] data, int offset) {
		intToFourBytes(Float.floatToIntBits(value), data, offset);
	}
	public static float bytesToFloat(byte[] bytes, int offset) {
		return Float.intBitsToFloat(bytesToInt(bytes, offset));
	}
	public static long bytesToLong(byte[] data, int offset) {
		return (long) ((long) (0xff & data[0 + offset]) << 56 | (long) (0xff & data[1 + offset]) << 48 | (long) (0xff & data[2 + offset]) << 40 | (long) (0xff & data[3 + offset]) << 32 | (long) (0xff & data[4 + offset]) << 24 | (long) (0xff & data[5 + offset]) << 16 | (long) (0xff & data[6 + offset]) << 8 | (long) (0xff & data[7 + offset]) << 0);
	}
	public static void longToEightBytes(long value, byte[] data, int offset) {
		data[offset] = (byte) (value >>> 56);
		data[offset + 1] = (byte) (value >>> 48);
		data[offset + 2] = (byte) (value >>> 40);
		data[offset + 3] = (byte) (value >>> 32);
		data[offset + 4] = (byte) (value >>> 24);
		data[offset + 5] = (byte) (value >>> 16);
		data[offset + 6] = (byte) (value >>> 8);
		data[offset + 7] = (byte) value;
	}
	public static long bytesToLong(byte[] ld) {
		return bytesToLong(ld, 0);
	}
	public static byte[] longToBytes(long l) {
		byte b[] = new byte[8];
		longToEightBytes(l, b, 0);
		return b;
	}
}
